package snapex.expense.controller;

import java.sql.Date;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import snapex.core.model.Expense;
import snapex.core.model.Result;
import snapex.core.model.SearchParams;
import snapex.expense.service.IExpenseService;
import snapex.expense.service.impl.HtcExpenseServiceFacade;

@Slf4j
@RestController
public class DashboardController {
	@Autowired
	private HtcExpenseServiceFacade htcExpenseService;
	
	@Autowired
	private IExpenseService expenseService;
	
	@ApiOperation(value="retrieve expense from e-expense and local")
	@GetMapping(value = "/expense/all",produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity listExpense(@RequestParam(required=false) String staffId, 
			@RequestParam(required=false) String expenseId,
			@RequestParam(required=false) Integer status, 
			@RequestParam(required=false) Date submittedDate, 
			@RequestParam(required=false) String projectId) throws Exception {
		
		SearchParams params = this.getSearchParams(staffId, expenseId, status, submittedDate, projectId, null);
		
		return this.listExpense(params);	
	}
	
	@ApiOperation(value="retrieve expense from e-expense and local")
	@PostMapping(value = "/expense/all",produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity listExpense(@RequestBody SearchParams params) throws Exception {
		
		if(params.getStaffId() != null) {		
			params.setUsername(DigestUtils.md5DigestAsHex(params.getStaffId().getBytes()));
		}
		
		log.debug("****listExpense***params={}",params);
		
		List<Expense> expenses = new ArrayList<Expense>(); 
		
		try {
			expenses.addAll(expenseService.getExpenses(params));
		}
		catch(Exception e) {
			log.error("Failed to get local expense",e);
		}
		
		try {
			expenses.addAll(htcExpenseService.getExpenses(params));
		}
		catch(Exception e) {
			log.error("Failed to get remote expense",e);
		}
		
		Expense[] all = expenses.toArray(new Expense[] {});
		
		Arrays.parallelSort(all, new Comparator<Expense>() {
				@Override
				public int compare(Expense o1, Expense o2) {				
					return o1.getExpenseId().compareTo(o2.getExpenseId());
				}
			}
		);
		
		return ResponseEntity.ok(Result.success().data(Arrays.asList(all)));		
	}
	
	@ApiOperation(value="retrieve expense from e-expense")
	@GetMapping(value = "/expense/remote", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity listRemoteExpense(@RequestParam(required=false) String staffId, 
			@RequestParam(required=false) String expenseId,
			@RequestParam(required=false) Integer status, 
			@RequestParam(required=false) Date submittedDate,
			@RequestParam(required=false) String projectId) throws Exception {	
		
		SearchParams params = this.getSearchParams(staffId, expenseId, status, submittedDate, projectId, null);
		
		return ResponseEntity.ok(htcExpenseService.getExpenses(params));		
	}
	
	@ApiOperation(value="retrieve expense from e-expense")
	@GetMapping(value = "/expense/local", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity listLocalExpense(@RequestParam(required=false) String staffId, 
			@RequestParam(required=false) String expenseId,
			@RequestParam(required=false) Integer status, 
			@RequestParam(required=false) Date submittedDate, 
			@RequestParam(required=false) String projectId,
			@RequestParam(required=false) String syncOnly) throws Exception {
		
		SearchParams params = this.getSearchParams(staffId, expenseId, status, submittedDate, projectId, syncOnly);
		
		return ResponseEntity.ok(expenseService.getExpenses(params));		
	}
		
	private SearchParams getSearchParams(String staffId, String expenseId,	Integer status,  Date submittedDate, String projectId, String syncOnly) {
		
		SearchParams params = new SearchParams();
		
		if(staffId != null) {		
			params.setUsername(DigestUtils.md5DigestAsHex(staffId.getBytes()));
		}
		
		params.setExpenseId(expenseId);
		params.setStatus(status);
		params.setSubmittedDate(submittedDate);
		params.setProjectId(projectId);
		params.setOnlyNotSync("Y".equalsIgnoreCase(syncOnly));
		
		return params;
	}
}
